package app.netmorphgui;

import java.io.FileNotFoundException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.event.ChangeEvent;
import netmorph.model.NetmorphModel;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JToggleButton;

import app.netmorphgui.tabs.IParameterTab;
import app.netmorphgui.tabs.JNetmorphParamTab;
import component.filedialog.AskFileDialog;

import netmorph.model.NetmorphExec;
import neuron.NetworkStatistics;
import neuron.Neuron;
import visualization.JNeuroView;

import common.statistics.Series;
import export.ImageToEPSExport;
import export.NeuronToHOCExport;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.event.ChangeListener;

public class NetmorphModelCreatorMain implements ActionListener {

    JNeuroView view;
    JNetmorphParamTab params;
    NetmorphModelView model;

    @Override
    public void actionPerformed(ActionEvent e) {

        if (e.getActionCommand().equals("REFRESH")) {


            try {
                if (!networkMode.isSelected()) {
                    model.setParam("V.pyramidal", "1");
                }
                model.initRun(NetmorphExec.DEFAULT_DIRNAME, 0);
                File neurons = model.runAndGet();
                view.openFile(neurons, null);

                // mark warnings
                for (IParameterTab tab : model.tabs()) {
                    tab.clearWarnings();
                }
                for (String w : model.getWarnings()) {
                    if (w.startsWith("Warning: Unused command")) {
                        String cmd = w.substring("Warning: Unused command".length()).trim();
                        cmd = cmd.split("=")[0];
                        for (IParameterTab tab : model.tabs()) {
                            tab.markWarning(cmd);
                        }
                    }
                }

                // modify icon
                ImageIcon img = Icons.renderWarnings(model.getWarnings().size());
                warningButton.setIcon(img);

                NetworkStatistics stats = NetmorphModel.parseResults(neurons);
                Series tsDist = stats.basalTermSegCountDist();
                System.out.println("#TS : " + tsDist.mean() + " +- " + tsDist.stdev() + " -> " + tsDist);
                for (double d : tsDist.values()) {
                    System.out.print(d + ", ");
                }
                System.out.println();


                status.append(String.format("Basal   TS %s, Asym %s, TS Len %s, IS Len %s\n",
                        stats.basalTermSegCountDist().formatNormDist(),
                        stats.basalAsymIndexDist().formatNormDist(),
                        stats.basalTermSegLenDist().formatNormDist(),
                        stats.basalIntSegLenDist().formatNormDist()));
                status.append(String.format("Oblique TS %s, Asym %s, TS Len %s, IS Len %s\n",
                        stats.obliqueTermSegCountDist().formatNormDist(),
                        stats.obliqueAsymIndexDist().formatNormDist(),
                        stats.obliqueTermSegLenDist().formatNormDist(),
                        stats.obliqueIntSegLenDist().formatNormDist()));
                status.append(String.format("Tuft    TS %s, Asym %s, TS Len %s, IS Len %s\n",
                        stats.tuftTermSegCountDist().formatNormDist(),
                        stats.tuftAsymIndexDist().formatNormDist(),
                        stats.tuftTermSegLenDist().formatNormDist(),
                        stats.tuftIntSegLenDist().formatNormDist()));
                status.append("  ***  \n");

            } catch (Exception e1) {
					e1.printStackTrace();
                JOptionPane.showMessageDialog(view, e1.getMessage());
            }

        } else if (e.getActionCommand().equals("SHOW.WARNINGS")) {
            if (model == null || model.getWarnings() == null) {
                return;
            }
            JList list = new JList(model.getWarnings().toArray(new String[model.getWarnings().size()]));
            JFrame jf = new JFrame("Warnings");
            JScrollPane jsp = new JScrollPane(list);
            jf.add(jsp);
            jf.setSize(512, 512);
            jf.setVisible(true);
        } else if (e.getActionCommand().equals("DIALOG.OPTIMIZE")) {
            new OptimizationDialog(model);
        } else if (e.getActionCommand().equals("EXPORT.IMAGE")) {

            JFileChooser jfc = new JFileChooser(System.getProperty("user.home"));
            jfc.setFileFilter(ImageToEPSExport.epsFilter);

            // show dialog
            int r = jfc.showSaveDialog(view);

            // if save pressed, save to file
            if (r == JFileChooser.APPROVE_OPTION) {

                ImageToEPSExport ex;
                if (view.getOpenNeuron() != null) {
                    ex = new ImageToEPSExport(view.getOpenNeuron());
                } else {
                    ex = new ImageToEPSExport(view.getOpenNetwork());
                }
                //			ex.setPlanes(AuxData.getPlanes(f));
                try {
                    ex.export(jfc.getSelectedFile());
                } catch (IOException e1) {
                    e1.printStackTrace();
                }

            }
        } else if (e.getActionCommand().equals("EXPORT.HOC")) {

            JFileChooser jfc = new JFileChooser(System.getProperty("user.home"));
            jfc.setFileFilter(NeuronToHOCExport.hocFilter);
				jfc.setDialogTitle("Save " + (view.getOpenNeuron() != null ? "single HOC" : "multiple HOCs"));
				
            // show dialog
            int r = jfc.showSaveDialog(view);

            // if save pressed, save to file
            if (r == JFileChooser.APPROVE_OPTION) {

                if (view.getOpenNeuron() != null) {
						 JOptionPane.showMessageDialog(view, "Exporting single neuron to HOC.");
                    NeuronToHOCExport hw = new NeuronToHOCExport();
                    hw.outputNeuron(view.getOpenNeuron());
                    try {
                        hw.save(jfc.getSelectedFile());
                    } catch (IOException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                } else if (view.getOpenNetwork() != null) {
						 JOptionPane.showMessageDialog(view, "Exporting " + view.getOpenNetwork().size() + " neuron(s) to HOC(s).");
                    int ni = 0;
                    String basename = jfc.getSelectedFile().getAbsolutePath().replaceAll("\\..*$", "");
                    for (Neuron n : view.getOpenNetwork()) {
							  if (!hocSeparate) {
									NeuronToHOCExport hw = new NeuronToHOCExport();
									hw.outputNeuron(n);
									try {
										 hw.save(new File(basename + "_" + ni + ".hoc"));
									} catch (IOException e1) {
										 e1.printStackTrace();
									}
							  } else {
									try {
										NeuronToHOCExport hw = new NeuronToHOCExport();
										hw.outputNeuron(n, true, true, false);
										 hw.save(new File(basename + "_" + ni + "_b.hoc"));

										 hw = new NeuronToHOCExport();
										hw.outputNeuron(n, true, false, true);
										 hw.save(new File(basename + "_" + ni + "_a.hoc"));
									} catch (IOException e1) {
										 e1.printStackTrace();
									}

							  }
                        ni++;
                    }
                }
            }
        }

    }
    JButton warningButton;
    JTextArea status;
    JToggleButton networkMode;

	 ActionListener menuListener = new ActionListener() {

		public void actionPerformed(ActionEvent ae) {
			if (ae.getActionCommand().equalsIgnoreCase("LOAD.CONFIG")) {
				File in = AskFileDialog.askTxtFile(frame, false);
				if (in != null) {
					try {
						model.loadConfig(in);
						model.updateTabs();
					} catch (FileNotFoundException ex) {
						Logger.getLogger(NetmorphModelCreatorMain.class.getName()).log(Level.SEVERE, null, ex);
					} catch (IOException ex) {
						Logger.getLogger(NetmorphModelCreatorMain.class.getName()).log(Level.SEVERE, null, ex);
					}
				}
			}
			if (ae.getActionCommand().equalsIgnoreCase("SAVE.CONFIG")) {
				File out = AskFileDialog.askTxtFile(frame, true);
				if (out != null) {
					try {
						model.saveConfig(out);
					} catch (FileNotFoundException ex) {
						Logger.getLogger(NetmorphModelCreatorMain.class.getName()).log(Level.SEVERE, null, ex);
					} catch (IOException ex) {
						Logger.getLogger(NetmorphModelCreatorMain.class.getName()).log(Level.SEVERE, null, ex);
					}
				}
			}
			if (ae.getActionCommand().equalsIgnoreCase("EXIT")) {
				frame.setVisible(false);
				System.exit(0);
			}
		}
	};

	 JFrame frame;
	 protected boolean hocSeparate = false;

    public NetmorphModelCreatorMain() {
        frame = new JFrame("Netmorph Model Creator v2010-10-03 (C) Risto Laakso 2010");
        frame.setSize(800, 600);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());

        // center - view
        view = new JNeuroView();

        frame.add(view, BorderLayout.CENTER);
        view.addCustomToolbarButton(new ImageIcon("icons/Refresh24.gif"), "Refresh Netmorph model", "REFRESH", this);

        warningButton = view.addCustomToolbarButton(new ImageIcon("icons/warning-icon.png"), "Show warnings", "SHOW.WARNINGS", this);

//        view.addCustomToolbarButton(new ImageIcon("icons/spreadsheet-icon.png"), "Optimize parameters..", "DIALOG.OPTIMIZE", this);

  //      view.addCustomToolbarButton(new ImageIcon("icons/Save24.gif"), "Save as EPS..", "EXPORT.IMAGE", this);

    //    view.addCustomToolbarButton(new ImageIcon("icons/Save24.gif"), "Save as HOC..", "EXPORT.HOC", this);

        networkMode = (JToggleButton) view.addCustomToolbarButton(null, "NET", "Network mode", "NETWORK", this, JToggleButton.class);

        // east - paramters
        model = new NetmorphModelView();
        params = new JNetmorphParamTab(model);
        frame.add(params, BorderLayout.WEST);

        // south - statistics / status
        status = new JTextArea();
        status.setEditable(false);
        status.setRows(5);
        status.setFont(new Font("monospaced", Font.PLAIN, 12));
        JScrollPane jsp = new JScrollPane(status);
        frame.add(jsp, BorderLayout.SOUTH);

		  
		  JMenuBar bar = new JMenuBar();
		  JMenu menu = new JMenu("File"); bar.add(menu);

		  JMenuItem item = new JMenuItem("Load config..");
		  item.setActionCommand("LOAD.CONFIG");
		  item.addActionListener(menuListener);
		  menu.add(item);

		  item = new JMenuItem("Save config..");
		  item.setActionCommand("SAVE.CONFIG");
		  item.addActionListener(menuListener);
		  menu.add(item);

		  item = new JMenuItem("Exit");
		  item.setActionCommand("EXIT");
		  item.addActionListener(menuListener);
		  menu.add(item);



		  menu = new JMenu("Options"); bar.add(menu);

		  final JCheckBoxMenuItem hocSepa = new JCheckBoxMenuItem("[HOC] Save basal/apical/obliques in separate files");
		  hocSepa.addChangeListener(new ChangeListener() {

			public void stateChanged(ChangeEvent ce) {
				hocSeparate = hocSepa.getState();
			}
			});
		  menu.add(hocSepa);


		  menu = new JMenu("Statistics"); bar.add(menu);

		  item = new JMenuItem("***");
		  item.setActionCommand("XX");
		  item.addActionListener(menuListener);
		  menu.add(item);


		  menu = new JMenu("Export"); bar.add(menu);

		  item = new JMenuItem("Save as Embedded Postscript (*.EPS)..");
		  item.setActionCommand("EXPORT.IMAGE");
		  item.addActionListener(this);
		  menu.add(item);

		  item = new JMenuItem("Save as NEURON file (*.HOC)..");
		  item.setActionCommand("EXPORT.HOC");
		  item.addActionListener(this);
		  menu.add(item);

		  item = new JMenuItem("Save as MATLAB file (*.MAT)..");
		  item.setActionCommand("EXPORT.MATLAB");
		  item.addActionListener(view);
		  menu.add(item);

		  frame.setJMenuBar(bar);

		  
        frame.setVisible(true);
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        new NetmorphModelCreatorMain();
    }
}
